#pragma once
#include<iostream>
#include<memory>
#include"Epoller.hpp"
#include"Socket.hpp"
#include"InetAddr.hpp"
#include"Log.hpp"
#include"Connection.hpp"

using func_t =std::function<std::string(std::string&)>;
class IOService :public Connection
{
    public:
    IOService(int sockfd)
    {
        SetSockfd(sockfd);
        SetEvents(EPOLLIN | EPOLLET);

    }
    void AppendInbuff(const std::string in)
    {
_inbuff+=in;
    }
    void AppendOutbuff(const std::string out)
    {
        _outbuff+=out;
    }
    virtual void Recever()override
    {
        LOG(LogLevel::INFO) << "Recever";
        while(true)
        {
            char buff[1024];
            ssize_t n = recv(_sockfd, buff, sizeof(buff), 0);
            if(n == -1)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;//本轮数据读完了
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else
                {
                    LOG(LogLevel::ERROR) << "recv error";
                    Excepter();
                    return;
                }
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "peer closed";
                Excepter();
                return;
            }
            else
            {
                buff[n]=0;
               AppendInbuff(buff);
            }
        }
        //确保是一个完整的报文
        std::string result;
        if(_on_message)
        result=_on_message(GetInBuff());
        if(result.empty())
        {
            //说明还没有读到一条完整的请求
            //那么继续while循环直到读取至少一条完整的报文
        }
        else
        {
            //说明已经读到至少一条完整的请求
            AppendOutbuff(result);
            //接受一开始是阻塞（接受缓冲区没数据），于是托转给多路转接进行等待，只有接受缓冲区有数据才会被唤醒，
            //发送一开始就可以发送（发送缓冲区有空间），当发送缓冲区满了（没有空间了）才会被阻塞，此时托转给多路转接进行等待
            //所以我们上来直接写，只有写入失败才说明发送区满了，此时才会被阻塞，需要交给多路转接
            if(_outbuff.empty()==0)
            {
                Sender();
            }
        }
    }
    void RegisterOnMessage(func_t on_message)
    {
        _on_message=on_message;
    }
    std::string& GetInBuff()
    {
        return _inbuff;
    }
    void DisCardOutBuff(int n)
    {
        _outbuff.erase(0,n);
    }
    virtual void Sender()override
    {
        while(true)
        {
            ssize_t n = send(Fd(), _outbuff.c_str(),_outbuff.size(), 0);
            if(n>0)
            {
                //发送成功了
                //如果我有100个字节，但是返回值n是10，说明对方满了
                DisCardOutBuff(n);
            }
            else if(n==0)
            {
                break;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else
                {
                    LOG(LogLevel::ERROR) << "send error";
                    Excepter();
                    return;
                }
            }
        }
        //情况1：outbuff已经发送玩了，
        //情况2：要么发送缓冲区被写满但是outbuff还没被清空
        if(!_outbuff.empty())
        {
            //写入是按需设置多路转接，只有outbuff不为空才需要epoll
            Owner()->EnableReadWrite(Fd(),1,1);
        }
        else
        {
            //outbuff已经发送完了，不需要epoll
            Owner()->EnableReadWrite(Fd(),1,0);
        }
    }
 
    virtual void Excepter()override
    {
        LOG(LogLevel::INFO) << "Excepter";
        //从Reactor移除connect，在epoll中取消对他的关心
        Owner()->DeleteConnection(Fd());
    }
    ~IOService()
    {}
    private:
    func_t _on_message;
};